﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Provausio.DependencyFinder.App.Wpf.Object.Domain;

namespace Provausio.DependencyFinder.App.Wpf.Logic
{
    public class DependencySearcher
    {
        private readonly XNamespace _csprojNamespace = @"http://schemas.microsoft.com/developer/msbuild/2003";

        public int Searched { get; private set; }

        public IEnumerable<Project> GetDependentProjects(string directory, Project checkDependency)
        {
            // get paths of all csproj files
            var projects = Directory.EnumerateFiles(directory, "*.csproj", SearchOption.AllDirectories).Select(path => new Project(path)).ToList();

            // read each file and grab projects that have a dependency
            var results = projects.Where(proj => HasDependency(proj, checkDependency)).ToList();

            // return project names
            Searched = projects.Count();
            return results;
        }

        private bool HasDependency(Project project, Project dependency)
        {
            var doc = XDocument.Load(project.ProjectPath);
            if (doc.Root == null) return false;

            return HasAssemblyReference(doc, dependency) || HasProjectReference(doc, dependency);
        }

        private bool HasAssemblyReference(XDocument doc, Project dependency)
        {
            if (doc.Root == null) return false;
            return
                doc.Root.Descendants(_csprojNamespace + "Reference")
                    .Select(reference => reference.Element(_csprojNamespace + "HintPath"))
                    .Any(xElement =>
                        xElement != null &&
                        xElement.Value.Contains(dependency.ProjectAssemblyName));
        }

        private bool HasProjectReference(XDocument doc, Project dependency)
        {
            if (doc.Root == null) return false;
            return
                doc.Root.Descendants(_csprojNamespace + "ProjectReference")
                        .Select(reference => reference.Element(_csprojNamespace + "Name"))
                        .Any(
                            projectName =>
                                projectName != null &&
                                projectName.Value.Equals(dependency.ProjectName, StringComparison.OrdinalIgnoreCase));
        }
    }
}
